/*
 * Swiper 2.7.5
 * Mobile touch slider and framework with hardware accelerated transitions
 *
 * http://www.idangero.us/sliders/swiper/
 *
 * Copyright 2010-2015, Vladimir Kharlampidi
 * The iDangero.us
 * http://www.idangero.us/
 *
 * Licensed under GPL & MIT
 *
 * Released on: January 4, 2015
 */

/*
 * Modified by chenglong.wang@yoho.cn on 2015/1/13
 */

    var Swiper = function(selector, params) {
        'use strict';

        /*=========================
          A little bit dirty but required part for IE8 and old FF support
          ===========================*/
        if (!document.body.outerHTML && document.body.__defineGetter__) {
            if (HTMLElement) {
                var element = HTMLElement.prototype;
                if (element.__defineGetter__) {
                    element.__defineGetter__('outerHTML', function() {
                        return new XMLSerializer().serializeToString(this);
                    });
                }
            }
        }

        if (!window.getComputedStyle) {
            window.getComputedStyle = function(el, pseudo) {
                this.el = el;
                this.getPropertyValue = function(prop) {
                    var re = /(\-([a-z]){1})/g;
                    if (prop === 'float') prop = 'styleFloat';
                    if (re.test(prop)) {
                        prop = prop.replace(re, function() {
                            return arguments[2].toUpperCase();
                        });
                    }
                    return el.currentStyle[prop] ? el.currentStyle[prop] : null;
                };
                return this;
            };
        }
        if (!Array.prototype.indexOf) {
            Array.prototype.indexOf = function(obj, start) {
                for (var i = (start || 0), j = this.length; i < j; i++) {
                    if (this[i] === obj) {
                        return i;
                    }
                }
                return -1;
            };
        }
        if (!document.querySelectorAll) {
            if (!window.jQuery) return;
        }

        function $$(selector, context) {
            if (document.querySelectorAll)
                return (context || document).querySelectorAll(selector);
            else
                return jQuery(selector, context);
        }

        /*=========================
          Check for correct selector
          ===========================*/
        if (typeof selector === 'undefined') return;

        if (!(selector.nodeType)) {
            if ($$(selector).length === 0) return;
        }

        /*=========================
         _this
         ===========================*/
        var _this = this;

        /*=========================
         Default Flags and vars
         ===========================*/
        _this.touches = {
            start: 0,
            startX: 0,
            startY: 0,
            current: 0,
            currentX: 0,
            currentY: 0,
            diff: 0,
            abs: 0
        };
        _this.positions = {
            start: 0,
            abs: 0,
            diff: 0,
            current: 0
        };
        _this.times = {
            start: 0,
            end: 0
        };

        _this.id = (new Date()).getTime();
        _this.container = (selector.nodeType) ? selector : $$(selector)[0];
        _this.isTouched = false;
        _this.isMoved = false;
        _this.activeIndex = 0;
        _this.centerIndex = 0;
        _this.activeLoaderIndex = 0;
        _this.activeLoopIndex = 0;
        _this.previousIndex = null;
        _this.velocity = 0;
        _this.snapGrid = [];
        _this.slidesGrid = [];
        _this.imagesToLoad = [];
        _this.imagesLoaded = 0;
        _this.wrapperLeft = 0;
        _this.wrapperRight = 0;
        _this.wrapperTop = 0;
        _this.wrapperBottom = 0;
        _this.isAndroid = navigator.userAgent.toLowerCase().indexOf('android') >= 0;
        var wrapper, slideSize, wrapperSize, direction, isScrolling, containerSize;

        /*=========================
          Default Parameters
          ===========================*/
        var defaults = {
            eventTarget: 'wrapper', // or 'container'
            mode: 'horizontal', // or 'vertical'
            touchRatio: 1,
            speed: 300,
            freeMode: false,
            freeModeFluid: false,
            momentumRatio: 1,
            momentumBounce: true,
            momentumBounceRatio: 1,
            slidesPerView: 1,
            slidesPerGroup: 1,
            slidesPerViewFit: true, //Fit to slide when spv "auto" and slides larger than container
            simulateTouch: true,
            followFinger: true,
            shortSwipes: true,
            longSwipesRatio: 0.5,
            moveStartThreshold: false,
            onlyExternal: false,
            createPagination: true,
            pagination: false,
            paginationElement: 'span',
            paginationClickable: false,
            paginationAsRange: true,
            resistance: true, // or false or 100%
            scrollContainer: false,
            preventLinks: true,
            preventLinksPropagation: false,
            noSwiping: false, // or class
            noSwipingClass: 'swiper-no-swiping', //:)
            initialSlide: 0,
            keyboardControl: false,
            mousewheelControl: false,
            mousewheelControlForceToAxis: false,
            useCSS3Transforms: true,
            // Autoplay
            autoplay: false,
            autoStopPlay: true, //当用户手动切换页面的时候是否自动停止播放
            autoplayDisableOnInteraction: true,
            autoplayStopOnLast: false,
            //Loop mode
            loop: false,
            loopAdditionalSlides: 0,
            // Round length values
            roundLengths: false,
            //Auto Height
            calculateHeight: false,
            //Apply CSS for width and/or height
            cssWidthAndHeight: false, // or true or 'width' or 'height'
            //Images Preloader
            updateOnImagesReady: true,
            //Form elements
            releaseFormElements: true,
            //Watch for active slide, useful when use effects on different slide states
            watchActiveIndex: false,
            //Slides Visibility Fit
            visibilityFullFit: false,
            //Slides Offset
            offsetPxBefore: 0,
            offsetPxAfter: 0,
            offsetSlidesBefore: 0,
            offsetSlidesAfter: 0,
            centeredSlides: false,
            //Queue callbacks
            queueStartCallbacks: false,
            queueEndCallbacks: false,
            //Auto Resize
            autoResize: true,
            resizeReInit: false,
            //DOMAnimation
            DOMAnimation: true,
            //Slides Loader
            loader: {
                slides: [], //array with slides
                slidesHTMLType: 'inner', // or 'outer'
                surroundGroups: 1, //keep preloaded slides groups around view
                logic: 'reload', //or 'change'
                loadAllSlides: false
            },
            // One way swipes
            swipeToPrev: true,
            swipeToNext: true,
            //Namespace
            slideElement: 'div',
            slideClass: 'swiper-slide',
            slideActiveClass: 'swiper-slide-active',
            slideVisibleClass: 'swiper-slide-visible',
            slideDuplicateClass: 'swiper-slide-duplicate',
            wrapperClass: 'swiper-wrapper',
            paginationElementClass: 'swiper-pagination-switch',
            paginationActiveClass: 'swiper-active-switch',
            paginationVisibleClass: 'swiper-visible-switch'
        };
        params = params || {};
        for (var prop in defaults) {
            if (prop in params && typeof params[prop] === 'object') {
                for (var subProp in defaults[prop]) {
                    if (!(subProp in params[prop])) {
                        params[prop][subProp] = defaults[prop][subProp];
                    }
                }
            } else if (!(prop in params)) {
                params[prop] = defaults[prop];
            }
        }
        _this.params = params;
        if (params.scrollContainer) {
            params.freeMode = true;
            params.freeModeFluid = true;
        }
        if (params.loop) {
            params.resistance = '100%';
        }
        var isH = params.mode === 'horizontal';

        /*=========================
          Define Touch Events
          ===========================*/
        var desktopEvents = ['mousedown', 'mousemove', 'mouseup'];
        if (_this.browser.ie10) desktopEvents = ['MSPointerDown', 'MSPointerMove', 'MSPointerUp'];
        if (_this.browser.ie11) desktopEvents = ['pointerdown', 'pointermove', 'pointerup'];

        _this.touchEvents = {
            touchStart: _this.support.touch || !params.simulateTouch ? 'touchstart' : desktopEvents[0],
            touchMove: _this.support.touch || !params.simulateTouch ? 'touchmove' : desktopEvents[1],
            touchEnd: _this.support.touch || !params.simulateTouch ? 'touchend' : desktopEvents[2]
        };

        /*=========================
          Wrapper
          ===========================*/
        for (var i = _this.container.childNodes.length - 1; i >= 0; i--) {
            if (_this.container.childNodes[i].className) {
                var _wrapperClasses = _this.container.childNodes[i].className.split(/\s+/);
                for (var j = 0; j < _wrapperClasses.length; j++) {
                    if (_wrapperClasses[j] === params.wrapperClass) {
                        wrapper = _this.container.childNodes[i];
                        wrapper.style.backgroundColor = "#fff";
                    }
                }
            }
        }

        _this.wrapper = wrapper;
        /*=========================
          Slide API
          ===========================*/
        _this._extendSwiperSlide = function(el) {
            el.append = function() {
                if (params.loop) {
                    el.insertAfter(_this.slides.length - _this.loopedSlides);
                } else {
                    _this.wrapper.appendChild(el);
                    _this.reInit();
                }

                return el;
            };
            el.prepend = function() {
                if (params.loop) {
                    _this.wrapper.insertBefore(el, _this.slides[_this.loopedSlides]);
                    _this.removeLoopedSlides();
                    _this.calcSlides();
                    _this.createLoop();
                } else {
                    _this.wrapper.insertBefore(el, _this.wrapper.firstChild);
                }
                _this.reInit();
                return el;
            };
            el.insertAfter = function(index) {
                if (typeof index === 'undefined') return false;
                var beforeSlide;

                if (params.loop) {
                    beforeSlide = _this.slides[index + 1 + _this.loopedSlides];
                    if (beforeSlide) {
                        _this.wrapper.insertBefore(el, beforeSlide);
                    } else {
                        _this.wrapper.appendChild(el);
                    }
                    _this.removeLoopedSlides();
                    _this.calcSlides();
                    _this.createLoop();
                } else {
                    beforeSlide = _this.slides[index + 1];
                    _this.wrapper.insertBefore(el, beforeSlide);
                }
                _this.reInit();
                return el;
            };
            el.clone = function() {
                return _this._extendSwiperSlide(el.cloneNode(true));
            };
            el.remove = function() {
                _this.wrapper.removeChild(el);
                _this.reInit();
            };
            el.html = function(html) {
                if (typeof html === 'undefined') {
                    return el.innerHTML;
                } else {
                    el.innerHTML = html;
                    return el;
                }
            };
            el.index = function() {
                var index;
                for (var i = _this.slides.length - 1; i >= 0; i--) {
                    if (el === _this.slides[i]) index = i;
                }
                return index;
            };
            el.isActive = function() {
                if (el.index() === _this.activeIndex) return true;
                else return false;
            };
            if (!el.swiperSlideDataStorage) el.swiperSlideDataStorage = {};
            el.getData = function(name) {
                return el.swiperSlideDataStorage[name];
            };
            el.setData = function(name, value) {
                el.swiperSlideDataStorage[name] = value;
                return el;
            };
            el.data = function(name, value) {
                if (typeof value === 'undefined') {
                    return el.getAttribute('data-' + name);
                } else {
                    el.setAttribute('data-' + name, value);
                    return el;
                }
            };
            el.getWidth = function(outer, round) {
                return _this.h.getWidth(el, outer, round);
            };
            el.getHeight = function(outer, round) {
                return _this.h.getHeight(el, outer, round);
            };
            el.getOffset = function() {
                return _this.h.getOffset(el);
            };
            return el;
        };

        //Calculate information about number of slides
        _this.calcSlides = function(forceCalcSlides) {
            var oldNumber = _this.slides ? _this.slides.length : false;
            _this.slides = [];
            _this.displaySlides = [];
            for (var i = 0; i < _this.wrapper.childNodes.length; i++) {
                if (_this.wrapper.childNodes[i].className) {
                    var _className = _this.wrapper.childNodes[i].className;
                    var _slideClasses = _className.split(/\s+/);
                    for (var j = 0; j < _slideClasses.length; j++) {
                        if (_slideClasses[j] === params.slideClass) {
                            _this.slides.push(_this.wrapper.childNodes[i]);
                        }
                    }
                }
            }
            for (i = _this.slides.length - 1; i >= 0; i--) {
                _this._extendSwiperSlide(_this.slides[i]);
            }
            if (oldNumber === false) return;
            if (oldNumber !== _this.slides.length || forceCalcSlides) {

                // Number of slides has been changed
                removeSlideEvents();
                addSlideEvents();
                _this.updateActiveSlide();
                if (_this.params.pagination) _this.createPagination();
                _this.callPlugins('numberOfSlidesChanged');
            }
        };

        //Create Slide
        _this.createSlide = function(html, slideClassList, el) {
            slideClassList = slideClassList || _this.params.slideClass;
            el = el || params.slideElement;
            var newSlide = document.createElement(el);
            newSlide.innerHTML = html || '';
            newSlide.className = slideClassList;
            return _this._extendSwiperSlide(newSlide);
        };

        //Append Slide
        _this.appendSlide = function(html, slideClassList, el) {
            if (!html) return;
            if (html.nodeType) {
                return _this._extendSwiperSlide(html).append();
            } else {
                return _this.createSlide(html, slideClassList, el).append();
            }
        };
        _this.prependSlide = function(html, slideClassList, el) {
            if (!html) return;
            if (html.nodeType) {
                return _this._extendSwiperSlide(html).prepend();
            } else {
                return _this.createSlide(html, slideClassList, el).prepend();
            }
        };
        _this.insertSlideAfter = function(index, html, slideClassList, el) {
            if (typeof index === 'undefined') return false;
            if (html.nodeType) {
                return _this._extendSwiperSlide(html).insertAfter(index);
            } else {
                return _this.createSlide(html, slideClassList, el).insertAfter(index);
            }
        };
        _this.removeSlide = function(index) {
            if (_this.slides[index]) {
                if (params.loop) {
                    if (!_this.slides[index + _this.loopedSlides]) return false;
                    _this.slides[index + _this.loopedSlides].remove();
                    _this.removeLoopedSlides();
                    _this.calcSlides();
                    _this.createLoop();
                } else _this.slides[index].remove();
                return true;
            } else return false;
        };
        _this.removeLastSlide = function() {
            if (_this.slides.length > 0) {
                if (params.loop) {
                    _this.slides[_this.slides.length - 1 - _this.loopedSlides].remove();
                    _this.removeLoopedSlides();
                    _this.calcSlides();
                    _this.createLoop();
                } else _this.slides[_this.slides.length - 1].remove();
                return true;
            } else {
                return false;
            }
        };
        _this.removeAllSlides = function() {
            var num = _this.slides.length;
            for (var i = _this.slides.length - 1; i >= 0; i--) {
                _this.slides[i].remove();
                if (i === num - 1) {
                    _this.setWrapperTranslate(0);
                }
            }
        };
        _this.getSlide = function(index) {
            return _this.slides[index];
        };
        _this.getLastSlide = function() {
            return _this.slides[_this.slides.length - 1];
        };
        _this.getFirstSlide = function() {
            return _this.slides[0];
        };

        //Currently Active Slide
        _this.activeSlide = function() {
            return _this.slides[_this.activeIndex];
        };

        /*=========================
         Wrapper for Callbacks : Allows additive callbacks via function arrays
         ===========================*/
        _this.fireCallback = function() {
            var callback = arguments[0];
            if (Object.prototype.toString.call(callback) === '[object Array]') {
                for (var i = 0; i < callback.length; i++) {
                    if (typeof callback[i] === 'function') {
                        callback[i].apply(arguments[1], [arguments[2], arguments[3], arguments[4], arguments[5]]);
                        //callback[i](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
                    }
                }
            } else if (Object.prototype.toString.call(callback) === '[object String]') {
                if (params['on' + callback]) _this.fireCallback(params['on' + callback], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
            } else {
                callback(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
                //console.log (typeof callback)
                // callback.apply(arguments[1], [arguments[2], arguments[3], arguments[4], arguments[5]]);
            }
        };

        function isArray(obj) {
            if (Object.prototype.toString.apply(obj) === '[object Array]') return true;
            return false;
        }

        /**
         * Allows user to add callbacks, rather than replace them
         * @param callback
         * @param func
         * @return {*}
         */
        _this.addCallback = function(callback, func) {
            var _this = this,
                tempFunc;
            if (_this.params['on' + callback]) {
                if (isArray(this.params['on' + callback])) {
                    return this.params['on' + callback].push(func);
                } else if (typeof this.params['on' + callback] === 'function') {
                    tempFunc = this.params['on' + callback];
                    this.params['on' + callback] = [];
                    this.params['on' + callback].push(tempFunc);
                    return this.params['on' + callback].push(func);
                }
            } else {
                this.params['on' + callback] = [];
                return this.params['on' + callback].push(func);
            }
        };
        _this.removeCallbacks = function(callback) {
            if (_this.params['on' + callback]) {
                _this.params['on' + callback] = null;
            }
        };

        /*=========================
          Plugins API
          ===========================*/
        var _plugins = [];
        //console.dir(_this.plugins);
        for (var plugin in _this.plugins) {
            if (params[plugin]) {
                var p = _this.plugins[plugin](_this, params[plugin]);
                if (p) _plugins.push(p);
            }
        }
        _this.callPlugins = function(method, args) {
            if (!args) args = {};
            for (var i = 0; i < _plugins.length; i++) {
                if (method in _plugins[i]) {
                    _plugins[i][method](args);
                }
            }
        };

        /*=========================
          Windows Phone 8 Fix
          ===========================*/
        if ((_this.browser.ie10 || _this.browser.ie11) && !params.onlyExternal) {
            _this.wrapper.classList.add('swiper-wp8-' + (isH ? 'horizontal' : 'vertical'));
        }

        /*=========================
          Free Mode Class
          ===========================*/
        if (params.freeMode) {
            _this.container.className += ' swiper-free-mode';
        }

        /*==================================================
            Init/Re-init/Resize Fix
        ====================================================*/
        _this.initialized = false;
        _this.init = function(force, forceCalcSlides) {
            var _width = _this.h.getWidth(_this.container, false, params.roundLengths);
            var _height = _this.h.getHeight(_this.container, false, params.roundLengths);
            if (_width === _this.width && _height === _this.height && !force) return;

            _this.width = _width;
            _this.height = _height;

            var slideWidth, slideHeight, slideMaxHeight, wrapperWidth, wrapperHeight, slideLeft;
            var i; // loop index variable to avoid JSHint W004 / W038
            containerSize = isH ? _width : _height;
            var wrapper = _this.wrapper;

            if (force) {
                _this.calcSlides(forceCalcSlides);
            }

            if (params.slidesPerView === 'auto') {
                //Auto mode
                var slidesWidth = 0;
                var slidesHeight = 0;

                //Unset Styles
                if (params.slidesOffset > 0) {
                    wrapper.style.paddingLeft = '';
                    wrapper.style.paddingRight = '';
                    wrapper.style.paddingTop = '';
                    wrapper.style.paddingBottom = '';
                }
                wrapper.style.width = '';
                wrapper.style.height = '';
                if (params.offsetPxBefore > 0) {
                    if (isH) _this.wrapperLeft = params.offsetPxBefore;
                    else _this.wrapperTop = params.offsetPxBefore;
                }
                if (params.offsetPxAfter > 0) {
                    if (isH) _this.wrapperRight = params.offsetPxAfter;
                    else _this.wrapperBottom = params.offsetPxAfter;
                }

                if (params.centeredSlides) {
                    if (isH) {
                        _this.wrapperLeft = (containerSize - this.slides[0].getWidth(true, params.roundLengths)) / 2;
                        _this.wrapperRight = (containerSize - _this.slides[_this.slides.length - 1].getWidth(true, params.roundLengths)) / 2;
                    } else {
                        _this.wrapperTop = (containerSize - _this.slides[0].getHeight(true, params.roundLengths)) / 2;
                        _this.wrapperBottom = (containerSize - _this.slides[_this.slides.length - 1].getHeight(true, params.roundLengths)) / 2;
                    }
                }

                if (isH) {
                    if (_this.wrapperLeft >= 0) wrapper.style.paddingLeft = _this.wrapperLeft + 'px';
                    if (_this.wrapperRight >= 0) wrapper.style.paddingRight = _this.wrapperRight + 'px';
                } else {
                    if (_this.wrapperTop >= 0) wrapper.style.paddingTop = _this.wrapperTop + 'px';
                    if (_this.wrapperBottom >= 0) wrapper.style.paddingBottom = _this.wrapperBottom + 'px';
                }
                slideLeft = 0;
                var centeredSlideLeft = 0;
                _this.snapGrid = [];
                _this.slidesGrid = [];

                slideMaxHeight = 0;
                for (i = 0; i < _this.slides.length; i++) {
                    slideWidth = _this.slides[i].getWidth(true, params.roundLengths);
                    slideHeight = _this.slides[i].getHeight(true, params.roundLengths);
                    if (params.calculateHeight) {
                        slideMaxHeight = Math.max(slideMaxHeight, slideHeight);
                    }
                    var _slideSize = isH ? slideWidth : slideHeight;
                    if (params.centeredSlides) {
                        var nextSlideWidth = i === _this.slides.length - 1 ? 0 : _this.slides[i + 1].getWidth(true, params.roundLengths);
                        var nextSlideHeight = i === _this.slides.length - 1 ? 0 : _this.slides[i + 1].getHeight(true, params.roundLengths);
                        var nextSlideSize = isH ? nextSlideWidth : nextSlideHeight;
                        if (_slideSize > containerSize) {
                            if (params.slidesPerViewFit) {
                                _this.snapGrid.push(slideLeft + _this.wrapperLeft);
                                _this.snapGrid.push(slideLeft + _slideSize - containerSize + _this.wrapperLeft);
                            } else {
                                for (var j = 0; j <= Math.floor(_slideSize / (containerSize + _this.wrapperLeft)); j++) {
                                    if (j === 0) _this.snapGrid.push(slideLeft + _this.wrapperLeft);
                                    else _this.snapGrid.push(slideLeft + _this.wrapperLeft + containerSize * j);
                                }
                            }
                            _this.slidesGrid.push(slideLeft + _this.wrapperLeft);
                        } else {
                            _this.snapGrid.push(centeredSlideLeft);
                            _this.slidesGrid.push(centeredSlideLeft);
                        }
                        centeredSlideLeft += _slideSize / 2 + nextSlideSize / 2;
                    } else {
                        if (_slideSize > containerSize) {
                            if (params.slidesPerViewFit) {
                                _this.snapGrid.push(slideLeft);
                                _this.snapGrid.push(slideLeft + _slideSize - containerSize);
                            } else {
                                if (containerSize !== 0) {
                                    for (var k = 0; k <= Math.floor(_slideSize / containerSize); k++) {
                                        _this.snapGrid.push(slideLeft + containerSize * k);
                                    }
                                } else {
                                    _this.snapGrid.push(slideLeft);
                                }
                            }

                        } else {
                            _this.snapGrid.push(slideLeft);
                        }
                        _this.slidesGrid.push(slideLeft);
                    }

                    slideLeft += _slideSize;

                    slidesWidth += slideWidth;
                    slidesHeight += slideHeight;
                }
                if (params.calculateHeight) _this.height = slideMaxHeight;
                if (isH) {
                    wrapperSize = slidesWidth + _this.wrapperRight + _this.wrapperLeft;
                    if (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'height') {
                        wrapper.style.width = (slidesWidth) + 'px';
                    }
                    if (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'width') {
                        wrapper.style.height = (_this.height) + 'px';
                    }
                } else {
                    if (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'height') {
                        wrapper.style.width = (_this.width) + 'px';
                    }
                    if (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'width') {
                        wrapper.style.height = (slidesHeight) + 'px';
                    }
                    wrapperSize = slidesHeight + _this.wrapperTop + _this.wrapperBottom;
                }

            } else if (params.scrollContainer) {
                //Scroll Container
                wrapper.style.width = '';
                wrapper.style.height = '';
                wrapperWidth = _this.slides[0].getWidth(true, params.roundLengths);
                wrapperHeight = _this.slides[0].getHeight(true, params.roundLengths);
                wrapperSize = isH ? wrapperWidth : wrapperHeight;
                wrapper.style.width = wrapperWidth + 'px';
                wrapper.style.height = wrapperHeight + 'px';
                slideSize = isH ? wrapperWidth : wrapperHeight;

            } else {
                //For usual slides
                if (params.calculateHeight) {
                    slideMaxHeight = 0;
                    wrapperHeight = 0;
                    //ResetWrapperSize
                    if (!isH) _this.container.style.height = '';
                    wrapper.style.height = '';

                    for (i = 0; i < _this.slides.length; i++) {
                        //ResetSlideSize
                        _this.slides[i].style.height = '';
                        slideMaxHeight = Math.max(_this.slides[i].getHeight(true), slideMaxHeight);
                        if (!isH) wrapperHeight += _this.slides[i].getHeight(true);
                    }
                    slideHeight = slideMaxHeight;
                    _this.height = slideHeight;

                    if (isH) wrapperHeight = slideHeight;
                    else {
                        containerSize = slideHeight;
                        _this.container.style.height = containerSize + 'px';
                    }
                } else {
                    slideHeight = isH ? _this.height : _this.height / params.slidesPerView;
                    if (params.roundLengths) slideHeight = Math.ceil(slideHeight);
                    wrapperHeight = isH ? _this.height : _this.slides.length * slideHeight;
                }
                slideWidth = isH ? _this.width / params.slidesPerView : _this.width;
                if (params.roundLengths) slideWidth = Math.ceil(slideWidth);
                wrapperWidth = isH ? _this.slides.length * slideWidth : _this.width;
                slideSize = isH ? slideWidth : slideHeight;

                if (params.offsetSlidesBefore > 0) {
                    if (isH) _this.wrapperLeft = slideSize * params.offsetSlidesBefore;
                    else _this.wrapperTop = slideSize * params.offsetSlidesBefore;
                }
                if (params.offsetSlidesAfter > 0) {
                    if (isH) _this.wrapperRight = slideSize * params.offsetSlidesAfter;
                    else _this.wrapperBottom = slideSize * params.offsetSlidesAfter;
                }
                if (params.offsetPxBefore > 0) {
                    if (isH) _this.wrapperLeft = params.offsetPxBefore;
                    else _this.wrapperTop = params.offsetPxBefore;
                }
                if (params.offsetPxAfter > 0) {
                    if (isH) _this.wrapperRight = params.offsetPxAfter;
                    else _this.wrapperBottom = params.offsetPxAfter;
                }
                if (params.centeredSlides) {
                    if (isH) {
                        _this.wrapperLeft = (containerSize - slideSize) / 2;
                        _this.wrapperRight = (containerSize - slideSize) / 2;
                    } else {
                        _this.wrapperTop = (containerSize - slideSize) / 2;
                        _this.wrapperBottom = (containerSize - slideSize) / 2;
                    }
                }
                if (isH) {
                    if (_this.wrapperLeft > 0) wrapper.style.paddingLeft = _this.wrapperLeft + 'px';
                    if (_this.wrapperRight > 0) wrapper.style.paddingRight = _this.wrapperRight + 'px';
                } else {
                    if (_this.wrapperTop > 0) wrapper.style.paddingTop = _this.wrapperTop + 'px';
                    if (_this.wrapperBottom > 0) wrapper.style.paddingBottom = _this.wrapperBottom + 'px';
                }

                wrapperSize = isH ? wrapperWidth + _this.wrapperRight + _this.wrapperLeft : wrapperHeight + _this.wrapperTop + _this.wrapperBottom;
                if (parseFloat(wrapperWidth) > 0 && (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'height')) {
                    wrapper.style.width = wrapperWidth + 'px';
                }
                if (parseFloat(wrapperHeight) > 0 && (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'width')) {
                    wrapper.style.height = wrapperHeight + 'px';
                }
                slideLeft = 0;
                _this.snapGrid = [];
                _this.slidesGrid = [];
                for (i = 0; i < _this.slides.length; i++) {
                    _this.snapGrid.push(slideLeft);
                    _this.slidesGrid.push(slideLeft);
                    slideLeft += slideSize;
                    if (parseFloat(slideWidth) > 0 && (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'height')) {
                        _this.slides[i].style.width = slideWidth + 'px';
                    }
                    if (parseFloat(slideHeight) > 0 && (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'width')) {
                        _this.slides[i].style.height = slideHeight + 'px';
                    }
                }

            }

            if (!_this.initialized) {
                _this.callPlugins('onFirstInit');
                if (params.onFirstInit) _this.fireCallback(params.onFirstInit, _this);
            } else {
                _this.callPlugins('onInit');
                if (params.onInit) _this.fireCallback(params.onInit, _this);
            }
            _this.initialized = true;
        };

        _this.reInit = function(forceCalcSlides) {
            _this.init(true, forceCalcSlides);
        };

        _this.resizeFix = function(reInit) {
            _this.callPlugins('beforeResizeFix');

            _this.init(params.resizeReInit || reInit);

            // swipe to active slide in fixed mode
            if (!params.freeMode) {
                _this.swipeTo((params.loop ? _this.activeLoopIndex : _this.activeIndex), 0, false);
                // Fix autoplay
                if (params.autoplay) {
                    if (_this.support.transitions && typeof autoplayTimeoutId !== 'undefined') {
                        if (typeof autoplayTimeoutId !== 'undefined') {
                            clearTimeout(autoplayTimeoutId);
                            autoplayTimeoutId = undefined;
                            _this.startAutoplay();
                        }
                    } else {
                        if (typeof autoplayIntervalId !== 'undefined') {
                            clearInterval(autoplayIntervalId);
                            autoplayIntervalId = undefined;
                            _this.startAutoplay();
                        }
                    }
                }
            }
            // move wrapper to the beginning in free mode
            else if (_this.getWrapperTranslate() < -maxWrapperPosition()) {
                _this.setWrapperTransition(0);
                _this.setWrapperTranslate(-maxWrapperPosition());
            }

            _this.callPlugins('afterResizeFix');
        };

        /*==========================================
            Max and Min Positions
        ============================================*/
        function maxWrapperPosition() {
            var a = (wrapperSize - containerSize);
            if (params.freeMode) {
                a = wrapperSize - containerSize;
            }
            // if (params.loop) a -= containerSize;
            if (params.slidesPerView > _this.slides.length && !params.centeredSlides) {
                a = 0;
            }
            if (a < 0) a = 0;
            return a;
        }

        /*==========================================
            Event Listeners
        ============================================*/
        function initEvents() {
            var bind = _this.h.addEventListener;
            var eventTarget = params.eventTarget === 'wrapper' ? _this.wrapper : _this.container;
            //Touch Events
            if (!(_this.browser.ie10 || _this.browser.ie11)) {
                if (_this.support.touch) {
                    bind(eventTarget, 'touchstart', onTouchStart);
                    bind(eventTarget, 'touchmove', onTouchMove);
                    bind(eventTarget, 'touchend', onTouchEnd);
                }
                if (params.simulateTouch) {
                    bind(eventTarget, 'mousedown', onTouchStart);
                    bind(document, 'mousemove', onTouchMove);
                    bind(document, 'mouseup', onTouchEnd);
                }
            } else {
                bind(eventTarget, _this.touchEvents.touchStart, onTouchStart);
                bind(document, _this.touchEvents.touchMove, onTouchMove);
                bind(document, _this.touchEvents.touchEnd, onTouchEnd);
            }

            //Resize Event
            if (params.autoResize) {
                bind(window, 'resize', _this.resizeFix);
            }
            //Slide Events
            addSlideEvents();
            //Mousewheel
            _this._wheelEvent = false;
            if (params.mousewheelControl) {
                if (document.onmousewheel !== undefined) {
                    _this._wheelEvent = 'mousewheel';
                }
                if (!_this._wheelEvent) {
                    try {
                        new WheelEvent('wheel');
                        _this._wheelEvent = 'wheel';
                    } catch (e) {}
                }
                if (!_this._wheelEvent) {
                    _this._wheelEvent = 'DOMMouseScroll';
                }
                if (_this._wheelEvent) {
                    bind(_this.container, _this._wheelEvent, handleMousewheel);
                }
            }

            //Keyboard
            function _loadImage(img) {
                var image, src;
                var onReady = function() {
                    if (typeof _this === 'undefined' || _this === null) return;
                    if (_this.imagesLoaded !== undefined) _this.imagesLoaded++;
                    if (_this.imagesLoaded === _this.imagesToLoad.length) {
                        _this.reInit();
                        if (params.onImagesReady) _this.fireCallback(params.onImagesReady, _this);
                    }
                };

                if (!img.complete) {
                    src = (img.currentSrc || img.getAttribute('src'));
                    if (src) {
                        image = new Image();
                        image.onload = onReady;
                        image.onerror = onReady;
                        image.src = src;
                    } else {
                        onReady();
                    }

                } else { //image already loaded...
                    onReady();
                }
            }

            if (params.keyboardControl) {
                bind(document, 'keydown', handleKeyboardKeys);
            }
            if (params.updateOnImagesReady) {
                _this.imagesToLoad = $$('img', _this.container);

                for (var i = 0; i < _this.imagesToLoad.length; i++) {
                    _loadImage(_this.imagesToLoad[i]);
                }
            }
        }

        //Remove Event Listeners
        _this.destroy = function(removeStyles) {
            var unbind = _this.h.removeEventListener;
            var eventTarget = params.eventTarget === 'wrapper' ? _this.wrapper : _this.container;
            //Touch Events
            if (!(_this.browser.ie10 || _this.browser.ie11)) {
                if (_this.support.touch) {
                    unbind(eventTarget, 'touchstart', onTouchStart);
                    unbind(eventTarget, 'touchmove', onTouchMove);
                    unbind(eventTarget, 'touchend', onTouchEnd);
                }
                if (params.simulateTouch) {
                    unbind(eventTarget, 'mousedown', onTouchStart);
                    unbind(document, 'mousemove', onTouchMove);
                    unbind(document, 'mouseup', onTouchEnd);
                }
            } else {
                unbind(eventTarget, _this.touchEvents.touchStart, onTouchStart);
                unbind(document, _this.touchEvents.touchMove, onTouchMove);
                unbind(document, _this.touchEvents.touchEnd, onTouchEnd);
            }

            //Resize Event
            if (params.autoResize) {
                unbind(window, 'resize', _this.resizeFix);
            }

            //Init Slide Events
            removeSlideEvents();

            //Pagination
            if (params.paginationClickable) {
                removePaginationEvents();
            }

            //Mousewheel
            if (params.mousewheelControl && _this._wheelEvent) {
                unbind(_this.container, _this._wheelEvent, handleMousewheel);
            }

            //Keyboard
            if (params.keyboardControl) {
                unbind(document, 'keydown', handleKeyboardKeys);
            }

            //Stop autoplay
            if (params.autoplay && params.autoStopPlay === true) {
                _this.stopAutoplay();
            }
            // Remove styles
            if (removeStyles) {
                _this.wrapper.removeAttribute('style');
                for (var i = 0; i < _this.slides.length; i++) {
                    _this.slides[i].removeAttribute('style');
                }
            }
            // Plugins
            _this.callPlugins('onDestroy');

            // Check jQuery/Zepto data
            if (window.jQuery && window.jQuery(_this.container).data('swiper')) {
                window.jQuery(_this.container).removeData('swiper');
            }
            if (window.Zepto && window.Zepto(_this.container).data('swiper')) {
                window.Zepto(_this.container).removeData('swiper');
            }

            //Destroy variable
            _this = null;
        };

        function addSlideEvents() {
            var bind = _this.h.addEventListener,
                i;

            //Prevent Links Events
            if (params.preventLinks) {
                var links = $$('a', _this.container);
                for (i = 0; i < links.length; i++) {
                    bind(links[i], 'click', preventClick);
                }
            }
            //Release Form Elements
            if (params.releaseFormElements) {
                var formElements = $$('input, textarea, select', _this.container);
                for (i = 0; i < formElements.length; i++) {
                    bind(formElements[i], _this.touchEvents.touchStart, releaseForms, true);
                    if (_this.support.touch && params.simulateTouch) {
                        bind(formElements[i], 'mousedown', releaseForms, true);
                    }
                }
            }

            //Slide Clicks & Touches
            if (params.onSlideClick) {
                for (i = 0; i < _this.slides.length; i++) {
                    bind(_this.slides[i], 'click', slideClick);
                }
            }
            if (params.onSlideTouch) {
                for (i = 0; i < _this.slides.length; i++) {
                    bind(_this.slides[i], _this.touchEvents.touchStart, slideTouch);
                }
            }
        }

        function removeSlideEvents() {
            var unbind = _this.h.removeEventListener,
                i;

            //Slide Clicks & Touches
            if (params.onSlideClick) {
                for (i = 0; i < _this.slides.length; i++) {
                    unbind(_this.slides[i], 'click', slideClick);
                }
            }
            if (params.onSlideTouch) {
                for (i = 0; i < _this.slides.length; i++) {
                    unbind(_this.slides[i], _this.touchEvents.touchStart, slideTouch);
                }
            }
            //Release Form Elements
            if (params.releaseFormElements) {
                var formElements = $$('input, textarea, select', _this.container);
                for (i = 0; i < formElements.length; i++) {
                    unbind(formElements[i], _this.touchEvents.touchStart, releaseForms, true);
                    if (_this.support.touch && params.simulateTouch) {
                        unbind(formElements[i], 'mousedown', releaseForms, true);
                    }
                }
            }
            //Prevent Links Events
            if (params.preventLinks) {
                var links = $$('a', _this.container);
                for (i = 0; i < links.length; i++) {
                    unbind(links[i], 'click', preventClick);
                }
            }
        }
        /*==========================================
            Keyboard Control
        ============================================*/
        function handleKeyboardKeys(e) {
            var kc = e.keyCode || e.charCode;
            if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) return;
            if (kc === 37 || kc === 39 || kc === 38 || kc === 40) {
                var inView = false;
                //Check that swiper should be inside of visible area of window
                var swiperOffset = _this.h.getOffset(_this.container);
                var scrollLeft = _this.h.windowScroll().left;
                var scrollTop = _this.h.windowScroll().top;
                var windowWidth = _this.h.windowWidth();
                var windowHeight = _this.h.windowHeight();
                var swiperCoord = [
                    [swiperOffset.left, swiperOffset.top],
                    [swiperOffset.left + _this.width, swiperOffset.top],
                    [swiperOffset.left, swiperOffset.top + _this.height],
                    [swiperOffset.left + _this.width, swiperOffset.top + _this.height]
                ];
                for (var i = 0; i < swiperCoord.length; i++) {
                    var point = swiperCoord[i];
                    if (
                        point[0] >= scrollLeft && point[0] <= scrollLeft + windowWidth &&
                        point[1] >= scrollTop && point[1] <= scrollTop + windowHeight
                    ) {
                        inView = true;
                    }

                }
                if (!inView) return;
            }
            if (isH) {
                if (kc === 37 || kc === 39) {
                    if (e.preventDefault) e.preventDefault();
                    else e.returnValue = false;
                }
                if (kc === 39) _this.swipeNext();
                if (kc === 37) _this.swipePrev();
            } else {
                if (kc === 38 || kc === 40) {
                    if (e.preventDefault) e.preventDefault();
                    else e.returnValue = false;
                }
                if (kc === 40) _this.swipeNext();
                if (kc === 38) _this.swipePrev();
            }
        }

        _this.disableKeyboardControl = function() {
            params.keyboardControl = false;
            _this.h.removeEventListener(document, 'keydown', handleKeyboardKeys);
        };

        _this.enableKeyboardControl = function() {
            params.keyboardControl = true;
            _this.h.addEventListener(document, 'keydown', handleKeyboardKeys);
        };

        /*==========================================
            Mousewheel Control
        ============================================*/
        var lastScrollTime = (new Date()).getTime();

        function handleMousewheel(e) {
            var we = _this._wheelEvent;
            var delta = 0;

            //Opera & IE
            if (e.detail) delta = -e.detail;
            //WebKits
            else if (we === 'mousewheel') {
                if (params.mousewheelControlForceToAxis) {
                    if (isH) {
                        if (Math.abs(e.wheelDeltaX) > Math.abs(e.wheelDeltaY)) delta = e.wheelDeltaX;
                        else return;
                    } else {
                        if (Math.abs(e.wheelDeltaY) > Math.abs(e.wheelDeltaX)) delta = e.wheelDeltaY;
                        else return;
                    }
                } else {
                    delta = e.wheelDelta;
                }
            }
            //Old FireFox
            else if (we === 'DOMMouseScroll') delta = -e.detail;
            //New FireFox
            else if (we === 'wheel') {
                if (params.mousewheelControlForceToAxis) {
                    if (isH) {
                        if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) delta = -e.deltaX;
                        else return;
                    } else {
                        if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) delta = -e.deltaY;
                        else return;
                    }
                } else {
                    delta = Math.abs(e.deltaX) > Math.abs(e.deltaY) ? -e.deltaX : -e.deltaY;
                }
            }

            if (!params.freeMode) {
                if ((new Date()).getTime() - lastScrollTime > 60) {
                    if (delta < 0) _this.swipeNext();
                    else _this.swipePrev();
                }
                lastScrollTime = (new Date()).getTime();

            } else {
                //Freemode or scrollContainer:
                var position = _this.getWrapperTranslate() + delta;

                if (position > 0) position = 0;
                if (position < -maxWrapperPosition()) position = -maxWrapperPosition();

                _this.setWrapperTransition(0);
                _this.setWrapperTranslate(position);
                _this.updateActiveSlide(position);

                // Return page scroll on edge positions
                if (position === 0 || position === -maxWrapperPosition()) return;
            }
            if (params.autoplay && params.autoStopPlay === true) _this.stopAutoplay(true);

            if (e.preventDefault) e.preventDefault();
            else e.returnValue = false;
            return false;
        }
        _this.disableMousewheelControl = function() {
            if (!_this._wheelEvent) return false;
            params.mousewheelControl = false;
            _this.h.removeEventListener(_this.container, _this._wheelEvent, handleMousewheel);
            return true;
        };

        _this.enableMousewheelControl = function() {
            if (!_this._wheelEvent) return false;
            params.mousewheelControl = true;
            _this.h.addEventListener(_this.container, _this._wheelEvent, handleMousewheel);
            return true;
        };

        /*=========================
          Grab Cursor
          ===========================*/
        if (params.grabCursor) {
            var containerStyle = _this.container.style;
            containerStyle.cursor = 'move';
            containerStyle.cursor = 'grab';
            containerStyle.cursor = '-moz-grab';
            containerStyle.cursor = '-webkit-grab';
        }

        /*=========================
          Slides Events Handlers
          ===========================*/

        _this.allowSlideClick = true;

        function slideClick(event) {
            if (_this.allowSlideClick) {
                setClickedSlide(event);
                _this.fireCallback(params.onSlideClick, _this, event);
            }
        }

        function slideTouch(event) {
            setClickedSlide(event);
            _this.fireCallback(params.onSlideTouch, _this, event);
        }

        function setClickedSlide(event) {

            // IE 6-8 support
            if (!event.currentTarget) {
                var element = event.srcElement;
                do {
                    if (element.className.indexOf(params.slideClass) > -1) {
                        break;
                    }
                    element = element.parentNode;
                } while (element);
                _this.clickedSlide = element;
            } else {
                _this.clickedSlide = event.currentTarget;
            }

            _this.clickedSlideIndex = _this.slides.indexOf(_this.clickedSlide);
            _this.clickedSlideLoopIndex = _this.clickedSlideIndex - (_this.loopedSlides || 0);
        }

        _this.allowLinks = true;

        function preventClick(e) {
            if (!_this.allowLinks) {
                if (e.preventDefault) e.preventDefault();
                else e.returnValue = false;
                if (params.preventLinksPropagation && 'stopPropagation' in e) {
                    e.stopPropagation();
                }
                return false;
            }
        }

        function releaseForms(e) {
            if (e.stopPropagation) e.stopPropagation();
            else e.returnValue = false;
            return false;

        }

        /*==================================================
            Event Handlers
        ====================================================*/
        var isTouchEvent = false;
        var allowThresholdMove;
        var allowMomentumBounce = true;

        function onTouchStart(event) {
            if (params.preventLinks) _this.allowLinks = true;
            //Exit if slider is already was touched
            if (_this.isTouched || params.onlyExternal) {
                return false;
            }

            // Blur active elements
            var eventTarget = event.target || event.srcElement;
            if (document.activeElement && document.activeElement !== document.body) {
                if (document.activeElement !== eventTarget) document.activeElement.blur();
            }

            // Form tag names
            var formTagNames = ('input select textarea').split(' ');

            // Check for no swiping
            if (params.noSwiping && (eventTarget) && noSwipingSlide(eventTarget)) return false;
            allowMomentumBounce = false;
            //Check For Nested Swipers
            _this.isTouched = true;
            isTouchEvent = event.type === 'touchstart';

            // prevent user enter with right and the swiper move (needs isTouchEvent)
            if (!isTouchEvent && 'which' in event && event.which === 3) {
                _this.isTouched = false;
                return false;
            }

            if (!isTouchEvent || event.targetTouches.length === 1) {
                _this.callPlugins('onTouchStartBegin');
                if (!isTouchEvent && !_this.isAndroid && formTagNames.indexOf(eventTarget.tagName.toLowerCase()) < 0) {

                    if (event.preventDefault) event.preventDefault();
                    else event.returnValue = false;
                }

                var pageX = isTouchEvent ? event.targetTouches[0].pageX : (event.pageX || event.clientX);
                var pageY = isTouchEvent ? event.targetTouches[0].pageY : (event.pageY || event.clientY);

                //Start Touches to check the scrolling
                _this.touches.startX = _this.touches.currentX = pageX;
                _this.touches.startY = _this.touches.currentY = pageY;

                _this.touches.start = _this.touches.current = isH ? pageX : pageY;

                //Set Transition Time to 0
                _this.setWrapperTransition(0);

                //Get Start Translate Position
                _this.positions.start = _this.positions.current = _this.getWrapperTranslate();

                //Set Transform
                _this.setWrapperTranslate(_this.positions.start);

                //TouchStartTime
                _this.times.start = (new Date()).getTime();

                //Unset Scrolling
                isScrolling = undefined;

                //Set Treshold
                if (params.moveStartThreshold > 0) {
                    allowThresholdMove = false;
                }

                //CallBack
                if (params.onTouchStart) _this.fireCallback(params.onTouchStart, _this, event);
                _this.callPlugins('onTouchStartEnd');

            }
        }
        var velocityPrevPosition, velocityPrevTime;

        function onTouchMove(event) {
            // If slider is not touched - exit
            if (!_this.isTouched || params.onlyExternal) return;
            if (isTouchEvent && event.type === 'mousemove') return;

            var pageX = isTouchEvent ? event.targetTouches[0].pageX : (event.pageX || event.clientX);
            var pageY = isTouchEvent ? event.targetTouches[0].pageY : (event.pageY || event.clientY);

            //check for scrolling
            if (typeof isScrolling === 'undefined' && isH) {
                isScrolling = !!(isScrolling || Math.abs(pageY - _this.touches.startY) > Math.abs(pageX - _this.touches.startX));
            }
            if (typeof isScrolling === 'undefined' && !isH) {
                isScrolling = !!(isScrolling || Math.abs(pageY - _this.touches.startY) < Math.abs(pageX - _this.touches.startX));
            }
            if (isScrolling) {
                _this.isTouched = false;
                return;
            }

            // One way swipes
            if (isH) {
                if ((!params.swipeToNext && pageX < _this.touches.startX) || ((!params.swipeToPrev && pageX > _this.touches.startX))) {
                    return;
                }
            } else {
                if ((!params.swipeToNext && pageY < _this.touches.startY) || ((!params.swipeToPrev && pageY > _this.touches.startY))) {
                    return;
                }
            }

            //Check For Nested Swipers
            if (event.assignedToSwiper) {
                _this.isTouched = false;
                return;
            }
            event.assignedToSwiper = true;

            //Block inner links
            if (params.preventLinks) {
                _this.allowLinks = false;
            }
            if (params.onSlideClick) {
                _this.allowSlideClick = false;
            }

            //Stop AutoPlay if exist
            if (params.autoplay && params.autoStopPlay === true) {
                _this.stopAutoplay(true);
            }
            if (!isTouchEvent || event.touches.length === 1) {

                //Moved Flag
                if (!_this.isMoved) {
                    _this.callPlugins('onTouchMoveStart');

                    if (params.loop) {
                        _this.fixLoop();
                        _this.positions.start = _this.getWrapperTranslate();
                    }
                    if (params.onTouchMoveStart) _this.fireCallback(params.onTouchMoveStart, _this);
                }
                _this.isMoved = true;

                // cancel event
                if (event.preventDefault) event.preventDefault();
                else event.returnValue = false;

                _this.touches.current = isH ? pageX : pageY;

                _this.positions.current = (_this.touches.current - _this.touches.start) * params.touchRatio + _this.positions.start;

                //Resistance Callbacks
                if (_this.positions.current > 0 && params.onResistanceBefore) {
                    _this.fireCallback(params.onResistanceBefore, _this, _this.positions.current);
                }
                if (_this.positions.current < -maxWrapperPosition() && params.onResistanceAfter) {
                    _this.fireCallback(params.onResistanceAfter, _this, Math.abs(_this.positions.current + maxWrapperPosition()));
                }
                //Resistance
                if (params.resistance && params.resistance !== '100%') {
                    var resistance;
                    //Resistance for Negative-Back sliding
                    if (_this.positions.current > 0) {
                        resistance = 1 - _this.positions.current / containerSize / 2;
                        if (resistance < 0.5)
                            _this.positions.current = (containerSize / 2);
                        else
                            _this.positions.current = _this.positions.current * resistance;
                    }
                    //Resistance for After-End Sliding
                    if (_this.positions.current < -maxWrapperPosition()) {

                        var diff = (_this.touches.current - _this.touches.start) * params.touchRatio + (maxWrapperPosition() + _this.positions.start);
                        resistance = (containerSize + diff) / (containerSize);
                        var newPos = _this.positions.current - diff * (1 - resistance) / 2;
                        var stopPos = -maxWrapperPosition() - containerSize / 2;

                        if (newPos < stopPos || resistance <= 0)
                            _this.positions.current = stopPos;
                        else
                            _this.positions.current = newPos;
                    }
                }
                if (params.resistance && params.resistance === '100%') {
                    //Resistance for Negative-Back sliding
                    if (_this.positions.current > 0 && !(params.freeMode && !params.freeModeFluid)) {
                        _this.positions.current = 0;
                    }
                    //Resistance for After-End Sliding
                    if (_this.positions.current < -maxWrapperPosition() && !(params.freeMode && !params.freeModeFluid)) {
                        _this.positions.current = -maxWrapperPosition();
                    }
                }
                //Move Slides
                if (!params.followFinger) return;

                if (!params.moveStartThreshold) {
                    _this.setWrapperTranslate(_this.positions.current);
                } else {
                    if (Math.abs(_this.touches.current - _this.touches.start) > params.moveStartThreshold || allowThresholdMove) {
                        if (!allowThresholdMove) {
                            allowThresholdMove = true;
                            _this.touches.start = _this.touches.current;
                            return;
                        }
                        _this.setWrapperTranslate(_this.positions.current);
                    } else {
                        _this.positions.current = _this.positions.start;
                    }
                }

                if (params.freeMode || params.watchActiveIndex) {
                    _this.updateActiveSlide(_this.positions.current);
                }

                //Grab Cursor
                if (params.grabCursor) {
                    _this.container.style.cursor = 'move';
                    _this.container.style.cursor = 'grabbing';
                    _this.container.style.cursor = '-moz-grabbin';
                    _this.container.style.cursor = '-webkit-grabbing';
                }
                //Velocity
                if (!velocityPrevPosition) velocityPrevPosition = _this.touches.current;
                if (!velocityPrevTime) velocityPrevTime = (new Date()).getTime();
                _this.velocity = (_this.touches.current - velocityPrevPosition) / ((new Date()).getTime() - velocityPrevTime) / 2;
                if (Math.abs(_this.touches.current - velocityPrevPosition) < 2) _this.velocity = 0;
                velocityPrevPosition = _this.touches.current;
                velocityPrevTime = (new Date()).getTime();
                //Callbacks
                _this.callPlugins('onTouchMoveEnd');
                if (params.onTouchMove) _this.fireCallback(params.onTouchMove, _this, event);

                return false;
            }
        }

        function onTouchEnd(event) {
            //Check For scrolling
            if (isScrolling) {
                _this.swipeReset();
            }
            // If slider is not touched exit
            if (params.onlyExternal || !_this.isTouched) return;
            _this.isTouched = false;

            //Return Grab Cursor
            if (params.grabCursor) {
                _this.container.style.cursor = 'move';
                _this.container.style.cursor = 'grab';
                _this.container.style.cursor = '-moz-grab';
                _this.container.style.cursor = '-webkit-grab';
            }

            //Check for Current Position
            if (!_this.positions.current && _this.positions.current !== 0) {
                _this.positions.current = _this.positions.start;
            }

            //For case if slider touched but not moved
            if (params.followFinger) {
                _this.setWrapperTranslate(_this.positions.current);
            }

            // TouchEndTime
            _this.times.end = (new Date()).getTime();

            //Difference
            _this.touches.diff = _this.touches.current - _this.touches.start;
            _this.touches.abs = Math.abs(_this.touches.diff);

            _this.positions.diff = _this.positions.current - _this.positions.start;
            _this.positions.abs = Math.abs(_this.positions.diff);

            var diff = _this.positions.diff;
            var diffAbs = _this.positions.abs;
            var timeDiff = _this.times.end - _this.times.start;

            if (diffAbs < 5 && (timeDiff) < 300 && _this.allowLinks === false) {
                if (!params.freeMode && diffAbs !== 0) _this.swipeReset();
                //Release inner links
                if (params.preventLinks) {
                    _this.allowLinks = true;
                }
                if (params.onSlideClick) {
                    _this.allowSlideClick = true;
                }
            }

            setTimeout(function() {
                //Release inner links
                if (typeof _this === 'undefined' || _this === null) return;
                if (params.preventLinks) {
                    _this.allowLinks = true;
                }
                if (params.onSlideClick) {
                    _this.allowSlideClick = true;
                }
            }, 100);

            var maxPosition = maxWrapperPosition();

            //Not moved or Prevent Negative Back Sliding/After-End Sliding
            if (!_this.isMoved && params.freeMode) {
                _this.isMoved = false;
                if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event);
                _this.callPlugins('onTouchEnd');
                return;
            }
            if (!_this.isMoved || _this.positions.current > 0 || _this.positions.current < -maxPosition) {
                _this.swipeReset();
                if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event);
                _this.callPlugins('onTouchEnd');
                return;
            }

            _this.isMoved = false;

            //Free Mode
            if (params.freeMode) {
                if (params.freeModeFluid) {
                    var momentumDuration = 1000 * params.momentumRatio;
                    var momentumDistance = _this.velocity * momentumDuration;
                    var newPosition = _this.positions.current + momentumDistance;
                    var doBounce = false;
                    var afterBouncePosition;
                    var bounceAmount = Math.abs(_this.velocity) * 20 * params.momentumBounceRatio;
                    if (newPosition < -maxPosition) {
                        if (params.momentumBounce && _this.support.transitions) {
                            if (newPosition + maxPosition < -bounceAmount) newPosition = -maxPosition - bounceAmount;
                            afterBouncePosition = -maxPosition;
                            doBounce = true;
                            allowMomentumBounce = true;
                        } else newPosition = -maxPosition;
                    }
                    if (newPosition > 0) {
                        if (params.momentumBounce && _this.support.transitions) {
                            if (newPosition > bounceAmount) newPosition = bounceAmount;
                            afterBouncePosition = 0;
                            doBounce = true;
                            allowMomentumBounce = true;
                        } else newPosition = 0;
                    }
                    //Fix duration
                    if (_this.velocity !== 0) momentumDuration = Math.abs((newPosition - _this.positions.current) / _this.velocity);

                    _this.setWrapperTranslate(newPosition);

                    _this.setWrapperTransition(momentumDuration);

                    if (params.momentumBounce && doBounce) {
                        _this.wrapperTransitionEnd(function() {
                            if (!allowMomentumBounce) return;
                            if (params.onMomentumBounce) _this.fireCallback(params.onMomentumBounce, _this);
                            _this.callPlugins('onMomentumBounce');

                            _this.setWrapperTranslate(afterBouncePosition);
                            _this.setWrapperTransition(300);
                        });
                    }

                    _this.updateActiveSlide(newPosition);
                }
                if (!params.freeModeFluid || timeDiff >= 300) _this.updateActiveSlide(_this.positions.current);

                if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event);
                _this.callPlugins('onTouchEnd');
                return;
            }

            //Direction
            direction = diff < 0 ? 'toNext' : 'toPrev';

            //Short Touches
            if (direction === 'toNext' && (timeDiff <= 300)) {
                if (diffAbs < 30 || !params.shortSwipes) _this.swipeReset();
                else _this.swipeNext(true, true);
            }

            if (direction === 'toPrev' && (timeDiff <= 300)) {
                if (diffAbs < 30 || !params.shortSwipes) _this.swipeReset();
                else _this.swipePrev(true, true);
            }

            //Long Touches
            var targetSlideSize = 0;
            if (params.slidesPerView === 'auto') {
                //Define current slide's width
                var currentPosition = Math.abs(_this.getWrapperTranslate());
                var slidesOffset = 0;
                var _slideSize;
                for (var i = 0; i < _this.slides.length; i++) {
                    _slideSize = isH ? _this.slides[i].getWidth(true, params.roundLengths) : _this.slides[i].getHeight(true, params.roundLengths);
                    slidesOffset += _slideSize;
                    if (slidesOffset > currentPosition) {
                        targetSlideSize = _slideSize;
                        break;
                    }
                }
                if (targetSlideSize > containerSize) targetSlideSize = containerSize;
            } else {
                targetSlideSize = slideSize * params.slidesPerView;
            }
            if (direction === 'toNext' && (timeDiff > 300)) {
                if (diffAbs >= targetSlideSize * params.longSwipesRatio) {
                    _this.swipeNext(true, true);
                } else {
                    _this.swipeReset();
                }
            }
            if (direction === 'toPrev' && (timeDiff > 300)) {
                if (diffAbs >= targetSlideSize * params.longSwipesRatio) {
                    _this.swipePrev(true, true);
                } else {
                    _this.swipeReset();
                }
            }
            if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event);
            _this.callPlugins('onTouchEnd');
        }


        /*==================================================
            noSwiping Bubble Check by Isaac Strack
        ====================================================*/
        function hasClass(el, classname) {
            return el && el.getAttribute('class') && el.getAttribute('class').indexOf(classname) > -1;
        }

        function noSwipingSlide(el) {
            /*This function is specifically designed to check the parent elements for the noSwiping class, up to the wrapper.
            We need to check parents because while onTouchStart bubbles, _this.isTouched is checked in onTouchStart, which stops the bubbling.
            So, if a text box, for example, is the initial target, and the parent slide container has the noSwiping class, the _this.isTouched
            check will never find it, and what was supposed to be noSwiping is able to be swiped.
            This function will iterate up and check for the noSwiping class in parents, up through the wrapperClass.*/

            // First we create a truthy variable, which is that swiping is allowd (noSwiping = false)
            var noSwiping = false;

            // Now we iterate up (parentElements) until we reach the node with the wrapperClass.
            do {

                // Each time, we check to see if there's a 'swiper-no-swiping' class (noSwipingClass).
                if (hasClass(el, params.noSwipingClass)) {
                    noSwiping = true; // If there is, we set noSwiping = true;
                }

                el = el.parentElement; // now we iterate up (parent node)

            } while (!noSwiping && el.parentElement && !hasClass(el, params.wrapperClass)); // also include el.parentElement truthy, just in case.

            // because we didn't check the wrapper itself, we do so now, if noSwiping is false:
            if (!noSwiping && hasClass(el, params.wrapperClass) && hasClass(el, params.noSwipingClass))
                noSwiping = true; // if the wrapper has the noSwipingClass, we set noSwiping = true;

            return noSwiping;
        }

        function addClassToHtmlString(klass, outerHtml) {
            var par = document.createElement('div');
            var child;

            par.innerHTML = outerHtml;
            child = par.firstChild;
            child.className += ' ' + klass;

            return child.outerHTML;
        }


        /*==================================================
            Swipe Functions
        ====================================================*/
        _this.swipeNext = function(runCallbacks, internal) {
            if (typeof runCallbacks === 'undefined') runCallbacks = true;
            if (!internal && params.loop) _this.fixLoop();
            if (!internal && params.autoplay && params.autoStopPlay === true) _this.stopAutoplay(true);
            _this.callPlugins('onSwipeNext');
            var currentPosition = _this.getWrapperTranslate().toFixed(2);
            var newPosition = currentPosition;
            if (params.slidesPerView === 'auto') {
                for (var i = 0; i < _this.snapGrid.length; i++) {
                    if (-currentPosition >= _this.snapGrid[i].toFixed(2) && -currentPosition < _this.snapGrid[i + 1].toFixed(2)) {
                        newPosition = -_this.snapGrid[i + 1];
                        break;
                    }
                }
            } else {
                var groupSize = slideSize * params.slidesPerGroup;
                newPosition = -(Math.floor(Math.abs(currentPosition) / Math.floor(groupSize)) * groupSize + groupSize);
            }
            if (newPosition < -maxWrapperPosition()) {
                newPosition = -maxWrapperPosition();
            }
            if (newPosition === currentPosition) return false;
            swipeToPosition(newPosition, 'next', {
                runCallbacks: runCallbacks
            });
            return true;
        };
        _this.swipePrev = function(runCallbacks, internal) {
            if (typeof runCallbacks === 'undefined') runCallbacks = true;
            if (!internal && params.loop) _this.fixLoop();
            if (!internal && params.autoplay && params.autoStopPlay === true) _this.stopAutoplay(true);
            _this.callPlugins('onSwipePrev');

            var currentPosition = Math.ceil(_this.getWrapperTranslate());
            var newPosition;
            if (params.slidesPerView === 'auto') {
                newPosition = 0;
                for (var i = 1; i < _this.snapGrid.length; i++) {
                    if (-currentPosition === _this.snapGrid[i]) {
                        newPosition = -_this.snapGrid[i - 1];
                        break;
                    }
                    if (-currentPosition > _this.snapGrid[i] && -currentPosition < _this.snapGrid[i + 1]) {
                        newPosition = -_this.snapGrid[i];
                        break;
                    }
                }
            } else {
                var groupSize = slideSize * params.slidesPerGroup;
                newPosition = -(Math.ceil(-currentPosition / groupSize) - 1) * groupSize;
            }

            if (newPosition > 0) newPosition = 0;

            if (newPosition === currentPosition) return false;
            swipeToPosition(newPosition, 'prev', {
                runCallbacks: runCallbacks
            });
            return true;

        };
        _this.swipeReset = function(runCallbacks) {
            if (typeof runCallbacks === 'undefined') runCallbacks = true;
            _this.callPlugins('onSwipeReset');
            var currentPosition = _this.getWrapperTranslate();
            var groupSize = slideSize * params.slidesPerGroup;
            var newPosition;
            var maxPosition = -maxWrapperPosition();
            if (params.slidesPerView === 'auto') {
                newPosition = 0;
                for (var i = 0; i < _this.snapGrid.length; i++) {
                    if (-currentPosition === _this.snapGrid[i]) return;
                    if (-currentPosition >= _this.snapGrid[i] && -currentPosition < _this.snapGrid[i + 1]) {
                        if (_this.positions.diff > 0) newPosition = -_this.snapGrid[i + 1];
                        else newPosition = -_this.snapGrid[i];
                        break;
                    }
                }
                if (-currentPosition >= _this.snapGrid[_this.snapGrid.length - 1]) newPosition = -_this.snapGrid[_this.snapGrid.length - 1];
                if (currentPosition <= -maxWrapperPosition()) newPosition = -maxWrapperPosition();
            } else {
                newPosition = currentPosition < 0 ? Math.round(currentPosition / groupSize) * groupSize : 0;
                if (currentPosition <= -maxWrapperPosition()) newPosition = -maxWrapperPosition();
            }
            if (params.scrollContainer) {
                newPosition = currentPosition < 0 ? currentPosition : 0;
            }
            if (newPosition < -maxWrapperPosition()) {
                newPosition = -maxWrapperPosition();
            }
            if (params.scrollContainer && (containerSize > slideSize)) {
                newPosition = 0;
            }

            if (newPosition === currentPosition) return false;

            swipeToPosition(newPosition, 'reset', {
                runCallbacks: runCallbacks
            });
            return true;
        };

        _this.swipeTo = function(index, speed, runCallbacks) {
            index = parseInt(index, 10);
            _this.callPlugins('onSwipeTo', {
                index: index,
                speed: speed
            });
            if (params.loop) index = index + _this.loopedSlides;
            var currentPosition = _this.getWrapperTranslate();
            if (index > (_this.slides.length - 1) || index < 0) return;
            var newPosition;
            if (params.slidesPerView === 'auto') {
                newPosition = -_this.slidesGrid[index];
            } else {
                newPosition = -index * slideSize;
            }
            if (newPosition < -maxWrapperPosition()) {
                newPosition = -maxWrapperPosition();
            }

            if (newPosition === currentPosition) return false;

            if (typeof runCallbacks === 'undefined') runCallbacks = true;
            swipeToPosition(newPosition, 'to', {
                index: index,
                speed: speed,
                runCallbacks: runCallbacks
            });
            return true;
        };

        function swipeToPosition(newPosition, action, toOptions) {
            var speed = (action === 'to' && toOptions.speed >= 0) ? toOptions.speed : params.speed;
            var timeOld = +new Date();

            function anim() {
                var timeNew = +new Date();
                var time = timeNew - timeOld;
                currentPosition += animationStep * time / (1000 / 60);
                condition = direction === 'toNext' ? currentPosition > newPosition : currentPosition < newPosition;
                if (condition) {
                    _this.setWrapperTranslate(Math.ceil(currentPosition));
                    _this._DOMAnimating = true;
                    window.setTimeout(function() {
                        anim();
                    }, 1000 / 60);
                } else {
                    if (params.onSlideChangeEnd) {
                        if (action === 'to') {
                            if (toOptions.runCallbacks === true) _this.fireCallback(params.onSlideChangeEnd, _this, direction);
                        } else {
                            _this.fireCallback(params.onSlideChangeEnd, _this, direction);
                        }

                    }
                    _this.setWrapperTranslate(newPosition);
                    _this._DOMAnimating = false;
                }
            }

            if (_this.support.transitions || !params.DOMAnimation) {
                _this.setWrapperTranslate(newPosition);
                _this.setWrapperTransition(speed);
            } else {
                //Try the DOM animation
                var currentPosition = _this.getWrapperTranslate();
                var animationStep = Math.ceil((newPosition - currentPosition) / speed * (1000 / 60));
                var direction = currentPosition > newPosition ? 'toNext' : 'toPrev';
                var condition = direction === 'toNext' ? currentPosition > newPosition : currentPosition < newPosition;
                if (_this._DOMAnimating) return;

                anim();
            }

            //Update Active Slide Index
            _this.updateActiveSlide(newPosition);

            //Callbacks
            if (params.onSlideNext && action === 'next' && toOptions.runCallbacks === true) {
                _this.fireCallback(params.onSlideNext, _this, newPosition);
            }
            if (params.onSlidePrev && action === 'prev' && toOptions.runCallbacks === true) {
                _this.fireCallback(params.onSlidePrev, _this, newPosition);
            }
            //'Reset' Callback
            if (params.onSlideReset && action === 'reset' && toOptions.runCallbacks === true) {
                _this.fireCallback(params.onSlideReset, _this, newPosition);
            }

            //'Next', 'Prev' and 'To' Callbacks
            if ((action === 'next' || action === 'prev' || action === 'to') && toOptions.runCallbacks === true)
                slideChangeCallbacks(action);
        }
        /*==================================================
            Transition Callbacks
        ====================================================*/
        //Prevent Multiple Callbacks
        _this._queueStartCallbacks = false;
        _this._queueEndCallbacks = false;

        function slideChangeCallbacks(direction) {
            //Transition Start Callback
            _this.callPlugins('onSlideChangeStart');
            if (params.onSlideChangeStart) {
                if (params.queueStartCallbacks && _this.support.transitions) {
                    if (_this._queueStartCallbacks) return;
                    _this._queueStartCallbacks = true;
                    _this.fireCallback(params.onSlideChangeStart, _this, direction);
                    _this.wrapperTransitionEnd(function() {
                        _this._queueStartCallbacks = false;
                    });
                } else _this.fireCallback(params.onSlideChangeStart, _this, direction);
            }
            //Transition End Callback
            if (params.onSlideChangeEnd) {
                if (_this.support.transitions) {
                    if (params.queueEndCallbacks) {
                        if (_this._queueEndCallbacks) return;
                        _this._queueEndCallbacks = true;
                        _this.wrapperTransitionEnd(function(swiper) {
                            _this.fireCallback(params.onSlideChangeEnd, swiper, direction);
                        });
                    } else {
                        _this.wrapperTransitionEnd(function(swiper) {
                            _this.fireCallback(params.onSlideChangeEnd, swiper, direction);
                        });
                    }
                } else {
                    if (!params.DOMAnimation) {
                        setTimeout(function() {
                            _this.fireCallback(params.onSlideChangeEnd, _this, direction);
                        }, 10);
                    }
                }
            }
        }

        /*==================================================
            Update Active Slide Index
        ====================================================*/
        _this.updateActiveSlide = function(position) {
            if (!_this.initialized) return;
            if (_this.slides.length === 0) return;
            _this.previousIndex = _this.activeIndex;
            if (typeof position === 'undefined') position = _this.getWrapperTranslate();
            if (position > 0) position = 0;
            var i;
            if (params.slidesPerView === 'auto') {
                var slidesOffset = 0;
                _this.activeIndex = _this.slidesGrid.indexOf(-position);
                if (_this.activeIndex < 0) {
                    for (i = 0; i < _this.slidesGrid.length - 1; i++) {
                        if (-position > _this.slidesGrid[i] && -position < _this.slidesGrid[i + 1]) {
                            break;
                        }
                    }
                    var leftDistance = Math.abs(_this.slidesGrid[i] + position);
                    var rightDistance = Math.abs(_this.slidesGrid[i + 1] + position);
                    if (leftDistance <= rightDistance) _this.activeIndex = i;
                    else _this.activeIndex = i + 1;
                }
            } else {
                _this.activeIndex = Math[params.visibilityFullFit ? 'ceil' : 'round'](-position / slideSize);
            }

            if (_this.activeIndex === _this.slides.length) _this.activeIndex = _this.slides.length - 1;
            if (_this.activeIndex < 0) _this.activeIndex = 0;

            // Check for slide
            if (!_this.slides[_this.activeIndex]) return;

            // Calc Visible slides
            _this.calcVisibleSlides(position);

            // Mark visible and active slides with additonal classes
            if (_this.support.classList) {
                var slide;
                for (i = 0; i < _this.slides.length; i++) {
                    slide = _this.slides[i];
                    slide.classList.remove(params.slideActiveClass);
                    if (_this.visibleSlides.indexOf(slide) >= 0) {
                        slide.classList.add(params.slideVisibleClass);
                    } else {
                        slide.classList.remove(params.slideVisibleClass);
                    }
                }
                _this.slides[_this.activeIndex].classList.add(params.slideActiveClass);
            } else {
                var activeClassRegexp = new RegExp('\\s*' + params.slideActiveClass);
                var inViewClassRegexp = new RegExp('\\s*' + params.slideVisibleClass);

                for (i = 0; i < _this.slides.length; i++) {
                    _this.slides[i].className = _this.slides[i].className.replace(activeClassRegexp, '').replace(inViewClassRegexp, '');
                    if (_this.visibleSlides.indexOf(_this.slides[i]) >= 0) {
                        _this.slides[i].className += ' ' + params.slideVisibleClass;
                    }
                }
                _this.slides[_this.activeIndex].className += ' ' + params.slideActiveClass;
            }

            //Update loop index
            if (params.loop) {
                var ls = _this.loopedSlides;
                _this.activeLoopIndex = _this.activeIndex - ls;
                if (_this.activeLoopIndex >= _this.slides.length - ls * 2) {
                    _this.activeLoopIndex = _this.slides.length - ls * 2 - _this.activeLoopIndex;
                }
                if (_this.activeLoopIndex < 0) {
                    _this.activeLoopIndex = _this.slides.length - ls * 2 + _this.activeLoopIndex;
                }
                if (_this.activeLoopIndex < 0) _this.activeLoopIndex = 0;
            } else {
                _this.activeLoopIndex = _this.activeIndex;
            }
            //Update Pagination
            if (params.pagination) {
                _this.updatePagination(position);
            }
        };
        /*==================================================
            Pagination
        ====================================================*/
        _this.createPagination = function(firstInit) {
            if (params.paginationClickable && _this.paginationButtons) {
                removePaginationEvents();
            }
            _this.paginationContainer = params.pagination.nodeType ? params.pagination : $$(params.pagination)[0];
            if (params.createPagination) {
                var paginationHTML = '';
                var numOfSlides = _this.slides.length;
                var numOfButtons = numOfSlides;
                if (params.loop) numOfButtons -= _this.loopedSlides * 2;
                for (var i = 0; i < numOfButtons; i++) {
                    paginationHTML += '<' + params.paginationElement + ' class="' + params.paginationElementClass + '"></' + params.paginationElement + '>';
                }
                _this.paginationContainer.innerHTML = paginationHTML;
            }
            _this.paginationButtons = $$('.' + params.paginationElementClass, _this.paginationContainer);
            if (!firstInit) _this.updatePagination();
            _this.callPlugins('onCreatePagination');
            if (params.paginationClickable) {
                addPaginationEvents();
            }
        };

        function removePaginationEvents() {
            var pagers = _this.paginationButtons;
            if (pagers) {
                for (var i = 0; i < pagers.length; i++) {
                    _this.h.removeEventListener(pagers[i], 'click', paginationClick);
                }
            }
        }

        function addPaginationEvents() {
            var pagers = _this.paginationButtons;
            if (pagers) {
                for (var i = 0; i < pagers.length; i++) {
                    _this.h.addEventListener(pagers[i], 'click', paginationClick);
                }
            }
        }

        function paginationClick(e) {
            var index;
            var target = e.target || e.srcElement;
            var pagers = _this.paginationButtons;
            for (var i = 0; i < pagers.length; i++) {
                if (target === pagers[i]) index = i;
            }
            if (params.autoplay && params.autoStopPlay === true) {
                _this.stopAutoplay(true);
            }
            _this.swipeTo(index);
        }
        _this.updatePagination = function(position) {
            if (!params.pagination) return;
            if (_this.slides.length < 1) return;
            var activePagers = $$('.' + params.paginationActiveClass, _this.paginationContainer);
            if (!activePagers) return;

            //Reset all Buttons' class to not active
            var pagers = _this.paginationButtons;
            if (pagers.length === 0) return;
            for (var i = 0; i < pagers.length; i++) {
                pagers[i].className = params.paginationElementClass;
            }

            var indexOffset = params.loop ? _this.loopedSlides : 0;
            if (params.paginationAsRange) {
                if (!_this.visibleSlides) _this.calcVisibleSlides(position);
                //Get Visible Indexes
                var visibleIndexes = [];
                var j; // lopp index - avoid JSHint W004 / W038
                for (j = 0; j < _this.visibleSlides.length; j++) {
                    var visIndex = _this.slides.indexOf(_this.visibleSlides[j]) - indexOffset;

                    if (params.loop && visIndex < 0) {
                        visIndex = _this.slides.length - _this.loopedSlides * 2 + visIndex;
                    }
                    if (params.loop && visIndex >= _this.slides.length - _this.loopedSlides * 2) {
                        visIndex = _this.slides.length - _this.loopedSlides * 2 - visIndex;
                        visIndex = Math.abs(visIndex);
                    }
                    visibleIndexes.push(visIndex);
                }

                for (j = 0; j < visibleIndexes.length; j++) {
                    if (pagers[visibleIndexes[j]]) pagers[visibleIndexes[j]].className += ' ' + params.paginationVisibleClass;
                }

                if (params.loop) {
                    if (pagers[_this.activeLoopIndex] !== undefined) {
                        pagers[_this.activeLoopIndex].className += ' ' + params.paginationActiveClass;
                    }
                } else {
                    if (pagers[_this.activeIndex]) pagers[_this.activeIndex].className += ' ' + params.paginationActiveClass;
                }
            } else {
                if (params.loop) {
                    if (pagers[_this.activeLoopIndex]) pagers[_this.activeLoopIndex].className += ' ' + params.paginationActiveClass + ' ' + params.paginationVisibleClass;
                } else {
                    if (pagers[_this.activeIndex]) pagers[_this.activeIndex].className += ' ' + params.paginationActiveClass + ' ' + params.paginationVisibleClass;
                }
            }
        };
        _this.calcVisibleSlides = function(position) {
            var visibleSlides = [];
            var _slideLeft = 0,
                _slideSize = 0,
                _slideRight = 0;
            if (isH && _this.wrapperLeft > 0) position = position + _this.wrapperLeft;
            if (!isH && _this.wrapperTop > 0) position = position + _this.wrapperTop;

            for (var i = 0; i < _this.slides.length; i++) {
                _slideLeft += _slideSize;
                if (params.slidesPerView === 'auto')
                    _slideSize = isH ? _this.h.getWidth(_this.slides[i], true, params.roundLengths) : _this.h.getHeight(_this.slides[i], true, params.roundLengths);
                else _slideSize = slideSize;

                _slideRight = _slideLeft + _slideSize;
                var isVisibile = false;
                if (params.visibilityFullFit) {
                    if (_slideLeft >= -position && _slideRight <= -position + containerSize) isVisibile = true;
                    if (_slideLeft <= -position && _slideRight >= -position + containerSize) isVisibile = true;
                } else {
                    if (_slideRight > -position && _slideRight <= ((-position + containerSize))) isVisibile = true;
                    if (_slideLeft >= -position && _slideLeft < ((-position + containerSize))) isVisibile = true;
                    if (_slideLeft < -position && _slideRight > ((-position + containerSize))) isVisibile = true;
                }

                if (isVisibile) visibleSlides.push(_this.slides[i]);

            }
            if (visibleSlides.length === 0) visibleSlides = [_this.slides[_this.activeIndex]];

            _this.visibleSlides = visibleSlides;
        };

        /*==========================================
            Autoplay
        ============================================*/
        var autoplayTimeoutId, autoplayIntervalId;
        _this.startAutoplay = function() {
            if (_this.support.transitions) {
                if (typeof autoplayTimeoutId !== 'undefined') return false;
                if (!params.autoplay) return;
                _this.callPlugins('onAutoplayStart');
                if (params.onAutoplayStart) _this.fireCallback(params.onAutoplayStart, _this);
                autoplay();
            } else {
                if (typeof autoplayIntervalId !== 'undefined') return false;
                if (!params.autoplay) return;
                _this.callPlugins('onAutoplayStart');
                if (params.onAutoplayStart) _this.fireCallback(params.onAutoplayStart, _this);
                autoplayIntervalId = setInterval(function() {
                    if (params.loop) {
                        _this.fixLoop();
                        _this.swipeNext(true, true);
                    } else if (!_this.swipeNext(true, true)) {
                        if (!params.autoplayStopOnLast) _this.swipeTo(0);
                        else {
                            clearInterval(autoplayIntervalId);
                            autoplayIntervalId = undefined;
                        }
                    }
                }, params.autoplay);
            }
        };
        _this.stopAutoplay = function(internal) {
            if (_this.support.transitions) {
                if (!autoplayTimeoutId) return;
                if (autoplayTimeoutId) clearTimeout(autoplayTimeoutId);
                autoplayTimeoutId = undefined;
                if (internal && !params.autoplayDisableOnInteraction) {
                    _this.wrapperTransitionEnd(function() {
                        autoplay();
                    });
                }
                _this.callPlugins('onAutoplayStop');
                if (params.onAutoplayStop) _this.fireCallback(params.onAutoplayStop, _this);
            } else {
                if (autoplayIntervalId) clearInterval(autoplayIntervalId);
                autoplayIntervalId = undefined;
                _this.callPlugins('onAutoplayStop');
                if (params.onAutoplayStop) _this.fireCallback(params.onAutoplayStop, _this);
            }
        };

        function autoplay() {
            autoplayTimeoutId = setTimeout(function() {
                if (params.loop) {
                    _this.fixLoop();
                    _this.swipeNext(true, true);
                } else if (!_this.swipeNext(true, true)) {
                    if (!params.autoplayStopOnLast) _this.swipeTo(0);
                    else {
                        clearTimeout(autoplayTimeoutId);
                        autoplayTimeoutId = undefined;
                    }
                }
                _this.wrapperTransitionEnd(function() {
                    if (typeof autoplayTimeoutId !== 'undefined') autoplay();
                });
            }, params.autoplay);
        }
        /*==================================================
            Loop
        ====================================================*/
        _this.loopCreated = false;
        _this.removeLoopedSlides = function() {
            if (_this.loopCreated) {
                for (var i = 0; i < _this.slides.length; i++) {
                    if (_this.slides[i].getData('looped') === true) _this.wrapper.removeChild(_this.slides[i]);
                }
            }
        };

        _this.createLoop = function() {
            if (_this.slides.length === 0) return;
            if (params.slidesPerView === 'auto') {
                _this.loopedSlides = params.loopedSlides || 1;
            } else {
                _this.loopedSlides = params.slidesPerView + params.loopAdditionalSlides;
            }

            if (_this.loopedSlides > _this.slides.length) {
                _this.loopedSlides = _this.slides.length;
            }

            var slideFirstHTML = '',
                slideLastHTML = '',
                i;
            var slidesSetFullHTML = '';
            /**
                    loopedSlides is too large if loopAdditionalSlides are set.
                    Need to divide the slides by maximum number of slides existing.

                    @author        Tomaz Lovrec <tomaz.lovrec@blanc-noir.at>
            */
            var numSlides = _this.slides.length;
            var fullSlideSets = Math.floor(_this.loopedSlides / numSlides);
            var remainderSlides = _this.loopedSlides % numSlides;
            // assemble full sets of slides
            for (i = 0; i < (fullSlideSets * numSlides); i++) {
                var j = i;
                if (i >= numSlides) {
                    var over = Math.floor(i / numSlides);
                    j = i - (numSlides * over);
                }
                slidesSetFullHTML += _this.slides[j].outerHTML;
            }
            // assemble remainder slides
            // assemble remainder appended to existing slides
            for (i = 0; i < remainderSlides; i++) {
                slideLastHTML += addClassToHtmlString(params.slideDuplicateClass, _this.slides[i].outerHTML);
            }
            // assemble slides that get preppended to existing slides
            for (i = numSlides - remainderSlides; i < numSlides; i++) {
                slideFirstHTML += addClassToHtmlString(params.slideDuplicateClass, _this.slides[i].outerHTML);
            }
            // assemble all slides
            var slides = slideFirstHTML + slidesSetFullHTML + wrapper.innerHTML + slidesSetFullHTML + slideLastHTML;
            // set the slides
            wrapper.innerHTML = slides;

            _this.loopCreated = true;
            _this.calcSlides();

            //Update Looped Slides with special class
            for (i = 0; i < _this.slides.length; i++) {
                if (i < _this.loopedSlides || i >= _this.slides.length - _this.loopedSlides) _this.slides[i].setData('looped', true);
            }
            _this.callPlugins('onCreateLoop');

        };

        _this.fixLoop = function() {
            var newIndex;
            //Fix For Negative Oversliding
            if (_this.activeIndex < _this.loopedSlides) {
                newIndex = _this.slides.length - _this.loopedSlides * 3 + _this.activeIndex;
                _this.swipeTo(newIndex, 0, false);
            }
            //Fix For Positive Oversliding
            else if ((params.slidesPerView === 'auto' && _this.activeIndex >= _this.loopedSlides * 2) || (_this.activeIndex > _this.slides.length - params.slidesPerView * 2)) {
                newIndex = -_this.slides.length + _this.activeIndex + _this.loopedSlides;
                _this.swipeTo(newIndex, 0, false);
            }
        };

        /*==================================================
            Slides Loader
        ====================================================*/
        _this.loadSlides = function() {
            var slidesHTML = '';
            _this.activeLoaderIndex = 0;
            var slides = params.loader.slides;
            var slidesToLoad = params.loader.loadAllSlides ? slides.length : params.slidesPerView * (1 + params.loader.surroundGroups);
            for (var i = 0; i < slidesToLoad; i++) {
                if (params.loader.slidesHTMLType === 'outer') slidesHTML += slides[i];
                else {
                    slidesHTML += '<' + params.slideElement + ' class="' + params.slideClass + '" data-swiperindex="' + i + '">' + slides[i] + '</' + params.slideElement + '>';
                }
            }
            _this.wrapper.innerHTML = slidesHTML;
            _this.calcSlides(true);
            //Add permanent transitionEnd callback
            if (!params.loader.loadAllSlides) {
                _this.wrapperTransitionEnd(_this.reloadSlides, true);
            }
        };

        _this.reloadSlides = function() {
            var slides = params.loader.slides;
            var newActiveIndex = parseInt(_this.activeSlide().data('swiperindex'), 10);
            if (newActiveIndex < 0 || newActiveIndex > slides.length - 1) return; //<-- Exit
            _this.activeLoaderIndex = newActiveIndex;
            var firstIndex = Math.max(0, newActiveIndex - params.slidesPerView * params.loader.surroundGroups);
            var lastIndex = Math.min(newActiveIndex + params.slidesPerView * (1 + params.loader.surroundGroups) - 1, slides.length - 1);
            //Update Transforms
            if (newActiveIndex > 0) {
                var newTransform = -slideSize * (newActiveIndex - firstIndex);
                _this.setWrapperTranslate(newTransform);
                _this.setWrapperTransition(0);
            }
            var i; // loop index
            //New Slides
            if (params.loader.logic === 'reload') {
                _this.wrapper.innerHTML = '';
                var slidesHTML = '';
                for (i = firstIndex; i <= lastIndex; i++) {
                    slidesHTML += params.loader.slidesHTMLType === 'outer' ? slides[i] : '<' + params.slideElement + ' class="' + params.slideClass + '" data-swiperindex="' + i + '">' + slides[i] + '</' + params.slideElement + '>';
                }
                _this.wrapper.innerHTML = slidesHTML;
            } else {
                var minExistIndex = 1000;
                var maxExistIndex = 0;

                for (i = 0; i < _this.slides.length; i++) {
                    var index = _this.slides[i].data('swiperindex');
                    if (index < firstIndex || index > lastIndex) {
                        _this.wrapper.removeChild(_this.slides[i]);
                    } else {
                        minExistIndex = Math.min(index, minExistIndex);
                        maxExistIndex = Math.max(index, maxExistIndex);
                    }
                }
                for (i = firstIndex; i <= lastIndex; i++) {
                    var newSlide;
                    if (i < minExistIndex) {
                        newSlide = document.createElement(params.slideElement);
                        newSlide.className = params.slideClass;
                        newSlide.setAttribute('data-swiperindex', i);
                        newSlide.innerHTML = slides[i];
                        _this.wrapper.insertBefore(newSlide, _this.wrapper.firstChild);
                    }
                    if (i > maxExistIndex) {
                        newSlide = document.createElement(params.slideElement);
                        newSlide.className = params.slideClass;
                        newSlide.setAttribute('data-swiperindex', i);
                        newSlide.innerHTML = slides[i];
                        _this.wrapper.appendChild(newSlide);
                    }
                }
            }
            //reInit
            _this.reInit(true);
        };

        /*==================================================
            Make Swiper
        ====================================================*/
        function makeSwiper() {
            _this.calcSlides();
            if (params.loader.slides.length > 0 && _this.slides.length === 0) {
                _this.loadSlides();
            }
            if (params.loop) {
                _this.createLoop();
            }
            _this.init();
            initEvents();
            if (params.pagination) {
                _this.createPagination(true);
            }

            if (params.loop || params.initialSlide > 0) {
                _this.swipeTo(params.initialSlide, 0, false);
            } else {
                _this.updateActiveSlide(0);
            }
            if (params.autoplay) {
                _this.startAutoplay();
            }
            /**
             * Set center slide index.
             *
             * @author        Tomaz Lovrec <tomaz.lovrec@gmail.com>
             */
            _this.centerIndex = _this.activeIndex;

            // Callbacks
            if (params.onSwiperCreated) _this.fireCallback(params.onSwiperCreated, _this);
            _this.callPlugins('onSwiperCreated');
        }

        makeSwiper();
    };

    Swiper.prototype = {
        plugins: {},

        /*==================================================
            Wrapper Operations
        ====================================================*/
        wrapperTransitionEnd: function(callback, permanent) {
            'use strict';
            var a = this,
                el = a.wrapper,
                events = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'],
                i;

            function fireCallBack(e) {
                if (e.target !== el) return;
                callback(a);
                if (a.params.queueEndCallbacks) a._queueEndCallbacks = false;
                if (!permanent) {
                    for (i = 0; i < events.length; i++) {
                        a.h.removeEventListener(el, events[i], fireCallBack);
                    }
                }
            }

            if (callback) {
                for (i = 0; i < events.length; i++) {
                    a.h.addEventListener(el, events[i], fireCallBack);
                }
            }
        },

        getWrapperTranslate: function(axis) {
            'use strict';
            var el = this.wrapper,
                matrix, curTransform, curStyle, transformMatrix;

            // automatic axis detection
            if (typeof axis === 'undefined') {
                axis = this.params.mode === 'horizontal' ? 'x' : 'y';
            }

            if (this.support.transforms && this.params.useCSS3Transforms) {
                curStyle = window.getComputedStyle(el, null);
                if (window.WebKitCSSMatrix) {
                    // Some old versions of Webkit choke when 'none' is passed; pass
                    // empty string instead in this case
                    transformMatrix = new WebKitCSSMatrix(curStyle.webkitTransform === 'none' ? '' : curStyle.webkitTransform);
                } else {
                    transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
                    matrix = transformMatrix.toString().split(',');
                }

                if (axis === 'x') {
                    //Latest Chrome and webkits Fix
                    if (window.WebKitCSSMatrix)
                        curTransform = transformMatrix.m41;
                    //Crazy IE10 Matrix
                    else if (matrix.length === 16)
                        curTransform = parseFloat(matrix[12]);
                    //Normal Browsers
                    else
                        curTransform = parseFloat(matrix[4]);
                }
                if (axis === 'y') {
                    //Latest Chrome and webkits Fix
                    if (window.WebKitCSSMatrix)
                        curTransform = transformMatrix.m42;
                    //Crazy IE10 Matrix
                    else if (matrix.length === 16)
                        curTransform = parseFloat(matrix[13]);
                    //Normal Browsers
                    else
                        curTransform = parseFloat(matrix[5]);
                }
            } else {
                if (axis === 'x') curTransform = parseFloat(el.style.left, 10) || 0;
                if (axis === 'y') curTransform = parseFloat(el.style.top, 10) || 0;
            }
            return curTransform || 0;
        },

        setWrapperTranslate: function(x, y, z) {
            'use strict';
            var es = this.wrapper.style,
                coords = {
                    x: 0,
                    y: 0,
                    z: 0
                },
                translate;

            // passed all coordinates
            if (arguments.length === 3) {
                coords.x = x;
                coords.y = y;
                coords.z = z;
            }

            // passed one coordinate and optional axis
            else {
                if (typeof y === 'undefined') {
                    y = this.params.mode === 'horizontal' ? 'x' : 'y';
                }
                coords[y] = x;
            }

            if (this.support.transforms && this.params.useCSS3Transforms) {
                translate = this.support.transforms3d ? 'translate3d(' + coords.x + 'px, ' + coords.y + 'px, ' + coords.z + 'px)' : 'translate(' + coords.x + 'px, ' + coords.y + 'px)';
                es.webkitTransform = es.MsTransform = es.msTransform = es.MozTransform = es.OTransform = es.transform = translate;
            } else {
                es.left = coords.x + 'px';
                es.top = coords.y + 'px';
            }
            this.callPlugins('onSetWrapperTransform', coords);
            if (this.params.onSetWrapperTransform) this.fireCallback(this.params.onSetWrapperTransform, this, coords);
        },

        setWrapperTransition: function(duration) {
            'use strict';
            var es = this.wrapper.style;
            es.webkitTransitionDuration = es.MsTransitionDuration = es.msTransitionDuration = es.MozTransitionDuration = es.OTransitionDuration = es.transitionDuration = (duration / 1000) + 's';
            this.callPlugins('onSetWrapperTransition', {
                duration: duration
            });
            if (this.params.onSetWrapperTransition) this.fireCallback(this.params.onSetWrapperTransition, this, duration);

        },

        /*==================================================
            Helpers
        ====================================================*/
        h: {
            getWidth: function(el, outer, round) {
                'use strict';
                var width = window.getComputedStyle(el, null).getPropertyValue('width');
                var returnWidth = parseFloat(width);
                //IE Fixes
                if (isNaN(returnWidth) || width.indexOf('%') > 0 || returnWidth < 0) {
                    returnWidth = el.offsetWidth - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-left')) - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-right'));
                }
                if (outer) returnWidth += parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-left')) + parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-right'));
                if (round) return Math.ceil(returnWidth);
                else return returnWidth;
            },
            getHeight: function(el, outer, round) {
                'use strict';
                if (outer) return el.offsetHeight;

                var height = window.getComputedStyle(el, null).getPropertyValue('height');
                var returnHeight = parseFloat(height);
                //IE Fixes
                if (isNaN(returnHeight) || height.indexOf('%') > 0 || returnHeight < 0) {
                    returnHeight = el.offsetHeight - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-top')) - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-bottom'));
                }
                if (outer) returnHeight += parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-top')) + parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-bottom'));
                if (round) return Math.ceil(returnHeight);
                else return returnHeight;
            },
            getOffset: function(el) {
                'use strict';
                var box = el.getBoundingClientRect();
                var body = document.body;
                var clientTop = el.clientTop || body.clientTop || 0;
                var clientLeft = el.clientLeft || body.clientLeft || 0;
                var scrollTop = window.pageYOffset || el.scrollTop;
                var scrollLeft = window.pageXOffset || el.scrollLeft;
                if (document.documentElement && !window.pageYOffset) {
                    //IE7-8
                    scrollTop = document.documentElement.scrollTop;
                    scrollLeft = document.documentElement.scrollLeft;
                }
                return {
                    top: box.top + scrollTop - clientTop,
                    left: box.left + scrollLeft - clientLeft
                };
            },
            windowWidth: function() {
                'use strict';
                if (window.innerWidth) return window.innerWidth;
                else if (document.documentElement && document.documentElement.clientWidth) return document.documentElement.clientWidth;
            },
            windowHeight: function() {
                'use strict';
                if (window.innerHeight) return window.innerHeight;
                else if (document.documentElement && document.documentElement.clientHeight) return document.documentElement.clientHeight;
            },
            windowScroll: function() {
                'use strict';
                if (typeof pageYOffset !== 'undefined') {
                    return {
                        left: window.pageXOffset,
                        top: window.pageYOffset
                    };
                } else if (document.documentElement) {
                    return {
                        left: document.documentElement.scrollLeft,
                        top: document.documentElement.scrollTop
                    };
                }
            },

            addEventListener: function(el, event, listener, useCapture) {
                'use strict';
                if (typeof useCapture === 'undefined') {
                    useCapture = false;
                }

                if (el.addEventListener) {
                    el.addEventListener(event, listener, useCapture);
                } else if (el.attachEvent) {
                    el.attachEvent('on' + event, listener);
                }
            },

            removeEventListener: function(el, event, listener, useCapture) {
                'use strict';
                if (typeof useCapture === 'undefined') {
                    useCapture = false;
                }

                if (el.removeEventListener) {
                    el.removeEventListener(event, listener, useCapture);
                } else if (el.detachEvent) {
                    el.detachEvent('on' + event, listener);
                }
            }
        },
        setTransform: function(el, transform) {
            'use strict';
            var es = el.style;
            es.webkitTransform = es.MsTransform = es.msTransform = es.MozTransform = es.OTransform = es.transform = transform;
        },
        setTranslate: function(el, translate) {
            'use strict';
            var es = el.style;
            var pos = {
                x: translate.x || 0,
                y: translate.y || 0,
                z: translate.z || 0
            };
            var transformString = this.support.transforms3d ? 'translate3d(' + (pos.x) + 'px,' + (pos.y) + 'px,' + (pos.z) + 'px)' : 'translate(' + (pos.x) + 'px,' + (pos.y) + 'px)';
            es.webkitTransform = es.MsTransform = es.msTransform = es.MozTransform = es.OTransform = es.transform = transformString;
            if (!this.support.transforms) {
                es.left = pos.x + 'px';
                es.top = pos.y + 'px';
            }
        },
        setTransition: function(el, duration) {
            'use strict';
            var es = el.style;
            es.webkitTransitionDuration = es.MsTransitionDuration = es.msTransitionDuration = es.MozTransitionDuration = es.OTransitionDuration = es.transitionDuration = duration + 'ms';
        },
        /*==================================================
            Feature Detection
        ====================================================*/
        support: {

            touch: (window.Modernizr && Modernizr.touch === true) || (function() {
                'use strict';
                return !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);
            })(),

            transforms3d: (window.Modernizr && Modernizr.csstransforms3d === true) || (function() {
                'use strict';
                var div = document.createElement('div').style;
                return ('webkitPerspective' in div || 'MozPerspective' in div || 'OPerspective' in div || 'MsPerspective' in div || 'perspective' in div);
            })(),

            transforms: (window.Modernizr && Modernizr.csstransforms === true) || (function() {
                'use strict';
                var div = document.createElement('div').style;
                return ('transform' in div || 'WebkitTransform' in div || 'MozTransform' in div || 'msTransform' in div || 'MsTransform' in div || 'OTransform' in div);
            })(),

            transitions: (window.Modernizr && Modernizr.csstransitions === true) || (function() {
                'use strict';
                var div = document.createElement('div').style;
                return ('transition' in div || 'WebkitTransition' in div || 'MozTransition' in div || 'msTransition' in div || 'MsTransition' in div || 'OTransition' in div);
            })(),

            classList: (function() {
                'use strict';
                var div = document.createElement('div');
                return 'classList' in div;
            })()
        },

        browser: {

            ie8: (function() {
                'use strict';
                var rv = -1; // Return value assumes failure.
                if (navigator.appName === 'Microsoft Internet Explorer') {
                    var ua = navigator.userAgent;
                    var re = new RegExp(/MSIE ([0-9]{1,}[\.0-9]{0,})/);
                    if (re.exec(ua) !== null)
                        rv = parseFloat(RegExp.$1);
                }
                return rv !== -1 && rv < 9;
            })(),

            ie10: window.navigator.msPointerEnabled,
            ie11: window.navigator.pointerEnabled
        }
    };

    /*=========================
      jQuery & Zepto Plugins
      ===========================*/
    if (window.jQuery || window.Zepto) {
        (function($) {
            'use strict';
            $.fn.swiper = function(params) {
                var firstInstance;
                this.each(function(i) {
                    var that = $(this);
                    var s = new Swiper(that[0], params);
                    if (!i) firstInstance = s;
                    that.data('swiper', s);
                });
                return firstInstance;
            };
        })(window.jQuery || window.Zepto);
    }

    // component
    if (typeof(module) !== 'undefined') {
        module.exports = Swiper;
    }

    // requirejs support
    if (typeof define === 'function' && define.amd) {
        define([], function() {
            'use strict';
            return Swiper;
        });
    }